/*
 ============================================================================
 Name		: P2PManager.cpp
 Author	  : 
 Version	 : 1.0
 Copyright   : 
 Description : CP2PManager implementation
 ============================================================================
 */

#include "P2PManager.h"

#include "P2PMessage.h"

#include "NfcConnector.h"

#include "Log.h"

CP2PManager::CP2PManager()
	{
	// No implementation required
	}

CP2PManager::~CP2PManager()
	{
	iConnector->Stop();
	delete iConnector;
	iConnector = 0;
	iSendQueue.ResetAndDestroy();
	iResponseMap.ResetAndDestroy();
	iTransactionLog.ResetAndDestroy();
	}

CP2PManager* CP2PManager::NewLC()
	{
	CP2PManager* self = new (ELeave) CP2PManager();
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

CP2PManager* CP2PManager::NewL()
	{
	CP2PManager* self = CP2PManager::NewLC();
	CleanupStack::Pop(); // self;
	return self;
	}

void CP2PManager::ConstructL()
	{
	iConnector = CNfcConnector::NewLC(this);
    iConnector->StartL();
	}

void CP2PManager::SendMessageL(const TDesC8& aAppId, const TDesC8& aMessageId, const TDesC8& aContent, TTime aValidUntil)
	{
	CP2PMessage* message = CP2PMessage::NewLC(CP2PMessage::EMessageToSend, aAppId, aMessageId, aContent, aValidUntil);
	iSendQueue.AppendL(message);
	CleanupStack::Pop(message);
	iConnector->ReadyToSend();
	}

void CP2PManager::SetResponseL(const TDesC8& aAppId, const TDesC8& aMessageId, const TDesC8& aContent, TTime aValidUntil)
	{
	CP2PMessage* response = CP2PMessage::NewLC(CP2PMessage::EResponseToSend, aAppId, aMessageId, aContent, aValidUntil);
	TInt exitingResponseIndex = iResponseMap.FindInOrder( response, CP2PMessage::ResponseMapOrder );
	if ( exitingResponseIndex != KErrNotFound )
		{
		delete iResponseMap[exitingResponseIndex];
		iResponseMap[exitingResponseIndex] = response;
		}
	else
		{
		iResponseMap.InsertInOrderL(response, CP2PMessage::ResponseMapOrder);
		}
	CleanupStack::Pop(response);
	}

HBufC8* CP2PManager::TransactionLogL(const TDesC8& aAppId) const
	{
	RBuf8 buffer;
	buffer.CreateL(16*1024);
	buffer.CleanupClosePushL();
	const TInt count = iTransactionLog.Count();
	buffer.Append(_L8("["));
	for (TInt i = 0; i < count; ++i)
		{
		if ( i != 0)
			{
			buffer.Append(_L8(",\n"));
			}
		HBufC8* transactionJson = iTransactionLog[i]->ToJSON();
		buffer.Append(*transactionJson);
		delete transactionJson;
		}
	buffer.Append(_L8("]"));
	HBufC8* result = buffer.AllocL();
	CleanupStack::PopAndDestroy(); // buffer;
	return result;
	}

void CP2PManager::ConnectionEstablished()
	{
	LOG1(_L8("Connection Established."));
	}

void CP2PManager::ConnectionLost()
	{
	LOG1(_L8("Connection Lost."));
	}

HBufC8* CP2PManager::GetNextMessagePayload()
	{
//	static bool sentOneMessage = false;
//	if (!sentOneMessage)
//		{
//		sentOneMessage = true;
//		return KMess;
//		}
	if (iSendQueue.Count() > 0)
		{
		iCurrentlySending = iSendQueue[0];
		iSendQueue.Remove(0);
		//TODO better memory handling
		if ( iCurrentlySending->Type() == CP2PMessage::EMessageToSend )
			{
			iCurrentlySending->SetType(CP2PMessage::EMessageSent);
			}
		else if ( iCurrentlySending->Type() == CP2PMessage::EResponseToSend )
			{
			iCurrentlySending->SetType(CP2PMessage::EResponseSent);
			}
		HBufC8* result = iCurrentlySending->SerializeL();
		return result;
		}
	return 0;
	}

void CP2PManager::MessageReceived(const TDesC8& aIncomingPayload)
	{
	LOG1(_L8("Message received:"));
	CP2PMessage* message = CP2PMessage::FromSerializedLC(aIncomingPayload);
	HBufC8* json = message->ToJSON();
	LOG2(_L8("%S\n"), json);
	delete json;
	if (message->Type() == CP2PMessage::EResponseSent)
		{
		message->SetType(CP2PMessage::EResponseReceived);
		}
	else if (message->Type() == CP2PMessage::EMessageSent)
		{
		message->SetType(CP2PMessage::EMessageReceived);
		const TInt responseIndex = iResponseMap.FindInOrder(message, CP2PMessage::ResponseMapOrder); 
		if ( responseIndex >= 0 )
			{
			CP2PMessage* response = iResponseMap[responseIndex];
			TInt error = iSendQueue.Insert( response, 0 );
			iResponseMap.Remove( responseIndex );
			if ( error == KErrNone )
				{
				iConnector->ReadyToSend();
				}
			else
				{
				delete response;
				}
			}
		}
	iTransactionLog.AppendL(message);
	CleanupStack::Pop(message);
	}

void CP2PManager::SendResult(TInt aError)
	{
	if ( aError == KErrNone )
		{
		LOG1(_L8("Message delivery successful"));
		if (iCurrentlySending) // TODO ASSERT here?
			{
			iTransactionLog.Append(iCurrentlySending);
			iCurrentlySending = 0;
			}
		}
	else
		{
		LOG2(_L8("Message delivery failed: %d"), aError);
		}
	}

